/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pos.system.ui;

/**
 *
 * @author shameera
 */
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.text.*;
import java.sql.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class StocksTable5 extends JFrame 
{
  protected JTable m_table;
  protected StockTableData m_data;
  protected JLabel m_title;

  public StocksTable5() {
    super("Stocks Table");
    setSize(600, 300);

    m_data = new StockTableData();

    m_title = new JLabel(m_data.getTitle(), 
      new ImageIcon("money.gif"), SwingConstants.LEFT);
    m_title.setFont(new Font("TimesRoman",Font.BOLD,24));
    m_title.setForeground(Color.black);
    getContentPane().add(m_title, BorderLayout.NORTH);

    m_table = new JTable();
    m_table.setAutoCreateColumnsFromModel(false);
    m_table.setModel(m_data); 
        
    for (int k = 0; k < StockTableData.m_columns.length; k++) {
      DefaultTableCellRenderer renderer = new 
        ColoredTableCellRenderer();
      renderer.setHorizontalAlignment(
        StockTableData.m_columns[k].m_alignment);
      TableColumn column = new TableColumn(k, 
      StockTableData.m_columns[k].m_width, renderer, null);
      m_table.addColumn(column);   
    }

    JTableHeader header = m_table.getTableHeader();
    header.setUpdateTableInRealTime(true);
    header.addMouseListener(m_data.new ColumnListener(m_table));
    header.setReorderingAllowed(true);

    JScrollPane ps = new JScrollPane();
    ps.getViewport().add(m_table);
    getContentPane().add(ps, BorderLayout.CENTER);

    JMenuBar menuBar = createMenuBar();
      setJMenuBar(menuBar);

    WindowListener wndCloser = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    };
    addWindowListener(wndCloser);
    setVisible(true);
  }

  protected JMenuBar createMenuBar() {
    JMenuBar menuBar = new JMenuBar();
        
    JMenu mFile = new JMenu("File");
    mFile.setMnemonic('f');

    JMenuItem mData = new JMenuItem("Retrieve Data...");
    mData.setMnemonic('r');
    ActionListener lstData = new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
        retrieveData(); 
      }
    };
    mData.addActionListener(lstData);
    mFile.add(mData);
    mFile.addSeparator();

    JMenuItem mExit = new JMenuItem("Exit");
    mExit.setMnemonic('x');
    ActionListener lstExit = new ActionListener() { 
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    };
    mExit.addActionListener(lstExit);
    mFile.add(mExit);
    menuBar.add(mFile);

    return menuBar;
  }

  public void retrieveData() {
    SimpleDateFormat frm = new SimpleDateFormat("MM/dd/yyyy");
    String currentDate = frm.format(m_data.m_date);
    String result = (String)JOptionPane.showInputDialog(this, 
      "Please enter date in form mm/dd/yyyy:", "Input", 
      JOptionPane.INFORMATION_MESSAGE, null, null, 
      currentDate);
    if (result==null)
      return;

    java.util.Date date = null;
    try { 
      date = frm.parse(result); 
    }
    catch (java.text.ParseException ex) { 
      date = null; 
    }
        
    if (date == null) {
      JOptionPane.showMessageDialog(this, 
        result+" is not a valid date",
        "Warning", JOptionPane.WARNING_MESSAGE);
      return;
    }

    setCursor( Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR) );
    switch (m_data.retrieveData(date)) {
      case 0:    // Ok with data
        m_title.setText(m_data.getTitle());
        m_table.tableChanged(new TableModelEvent(m_data)); 
        m_table.repaint();
        break;
      case 1: // No data
        JOptionPane.showMessageDialog(this, 
          "No data found for "+result,
          "Warning", JOptionPane.WARNING_MESSAGE);
        break;
      case -1: // Error
        JOptionPane.showMessageDialog(this, 
          "Error retrieving data",
          "Warning", JOptionPane.WARNING_MESSAGE);
        break;
    }
    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  }

  public static void main(String argv[]) {
    new StocksTable5();
  }
}

class ColoredTableCellRenderer extends DefaultTableCellRenderer
{
  public void setValue(Object value) 
  {
    if (value instanceof ColorData) {
      ColorData cvalue = (ColorData)value;
      setForeground(cvalue.m_color);
      setText(cvalue.m_data.toString());
    }
    else if (value instanceof IconData) {
      IconData ivalue = (IconData)value;
      setIcon(ivalue.m_icon);
      setText(ivalue.m_data.toString());
    }
    else
      super.setValue(value);
  }
}

class Fraction
{
  public int m_whole;
  public int m_nom;
  public int m_den;

  public Fraction(double value) {
    int sign = value <0 ? -1 : 1;
    value = Math.abs(value);
    m_whole = (int)value;
    m_den = 32;
    m_nom = (int)((value-m_whole)*m_den);
    while (m_nom!=0 && m_nom%2==0) {
      m_nom /= 2;
      m_den /= 2;
    }
    if (m_whole==0)
      m_nom *= sign;
    else
      m_whole *= sign;
  }

  public double doubleValue() {
    return (double)m_whole + (double)m_nom/m_den;
  }

  public String toString() {
    if (m_nom==0)
      return ""+m_whole;
    else if (m_whole==0)
      return ""+m_nom+"/"+m_den;
    else
      return ""+m_whole+" "+m_nom+"/"+m_den;
  }
}

class SmartLong
{
  protected static NumberFormat FORMAT;
  static {
    FORMAT = NumberFormat.getInstance();
    FORMAT.setGroupingUsed(true);
  }

  public long m_value;

  public SmartLong(long value) { m_value = value; }

  public long longValue() { return m_value; }

  public String toString() { return FORMAT.format(m_value); }
}


class ColorData
{
  public Color  m_color;
  public Object m_data;
  public static Color GREEN = new Color(0, 128, 0);
  public static Color RED = Color.red;

  public ColorData(Fraction data) {
    m_color = data.doubleValue() >= 0 ? GREEN : RED;
    m_data  = data;
  }

  public ColorData(Color color, Object data) {
    m_color = color;
    m_data  = data;
  }
    
  public ColorData(Double data) {
    m_color = data.doubleValue() >= 0 ? GREEN : RED;
    m_data  = data;
  }
    
  public String toString() {
    return m_data.toString();
  }
}

class IconData
{
  public ImageIcon  m_icon;
  public Object m_data;

  public IconData(ImageIcon icon, Object data) {
    m_icon = icon;
    m_data = data;
  }
    
  public String toString() {
    return m_data.toString();
  }
}

class StockData
{
  public static ImageIcon ICON_UP = new ImageIcon("ArrUp.gif");
  public static ImageIcon ICON_DOWN = new ImageIcon("ArrDown.gif");
  public static ImageIcon ICON_BLANK = new ImageIcon("blank.gif");

  public IconData  m_symbol;
  public String  m_name;
  public Fraction  m_last;
  public Fraction  m_open;
  public ColorData  m_change;
  public ColorData  m_changePr;
  public SmartLong  m_volume;

  public StockData(String symbol, String name, double last, 
   double open, double change, double changePr, long volume) {
    m_symbol = new IconData(getIcon(change), symbol);
    m_name = name;
    m_last = new Fraction(last);
    m_open = new Fraction(open);
    m_change = new ColorData(new Fraction(change));
    m_changePr = new ColorData(new Double(changePr));
    m_volume = new SmartLong(volume);
  }

  public static ImageIcon getIcon(double change) {
    return (change>0 ? ICON_UP : (change<0 ? ICON_DOWN : 
      ICON_BLANK));
  }
}


class ColumnData_ex
{
  public String  m_title;
  public int     m_width;
  public int     m_alignment;

  public ColumnData_ex(String title, int width, int alignment) {
    m_title = title;
    m_width = width;
    m_alignment = alignment;
  }
}

class StockTableData extends AbstractTableModel 
{
  static final public ColumnData_ex m_columns[] = {
    new ColumnData_ex( "Symbol", 100, JLabel.LEFT ),
    new ColumnData_ex( "Name", 160, JLabel.LEFT ),
    new ColumnData_ex( "Last", 100, JLabel.RIGHT ),
    new ColumnData_ex( "Open", 100, JLabel.RIGHT ),
    new ColumnData_ex( "Change", 100, JLabel.RIGHT ),
    new ColumnData_ex( "Change %", 100, JLabel.RIGHT ),
    new ColumnData_ex( "Volume", 100, JLabel.RIGHT )
  };

  protected SimpleDateFormat m_frm;
  protected Vector m_vector;
  protected java.util.Date m_date;

  protected int m_sortCol = 0;
  protected boolean m_sortAsc = true;

  protected int m_result = 0;

  public StockTableData() {
    m_frm = new SimpleDateFormat("MM/dd/yyyy");
    m_vector = new Vector();
    setDefaultData();
  }

  public void setDefaultData() {
    try { 
      m_date = m_frm.parse("4/6/1999"); 
    }
    catch (java.text.ParseException ex) { 
      m_date = null; 
    }

    m_vector.removeAllElements();
    m_vector.addElement(new StockData("ORCL", "Oracle Corp.", 
      23.6875, 25.375, -1.6875, -6.42, 24976600));
    m_vector.addElement(new StockData("EGGS", "Egghead.com", 
      17.25, 17.4375, -0.1875, -1.43, 2146400));
    m_vector.addElement(new StockData("T", "AT&T", 
      65.1875, 66, -0.8125, -0.10, 554000));
    m_vector.addElement(new StockData("LU", "Lucent Technology", 
      64.625, 59.9375, 4.6875, 9.65, 29856300));
    m_vector.addElement(new StockData("FON", "Sprint", 
      104.5625, 106.375, -1.8125, -1.82, 1135100));
    m_vector.addElement(new StockData("ENML", "Enamelon Inc.", 
      4.875, 5, -0.125, 0, 35900)); 
    m_vector.addElement(new StockData("CPQ", "Compaq Computers", 
      30.875, 31.25, -0.375, -2.18, 11853900));
    m_vector.addElement(new StockData("MSFT", "Microsoft Corp.", 
      94.0625, 95.1875, -1.125, -0.92, 19836900));
    m_vector.addElement(new StockData("DELL", "Dell Computers", 
      46.1875, 44.5, 1.6875, 6.24, 47310000));
    m_vector.addElement(new StockData("SUNW", "Sun Microsystems", 
      140.625, 130.9375, 10, 10.625, 17734600));
    m_vector.addElement(new StockData("IBM", "Intl. Bus. Machines", 
      183, 183.125, -0.125, -0.51, 4371400));
    m_vector.addElement(new StockData("HWP", "Hewlett-Packard", 
      70, 71.0625, -1.4375, -2.01, 2410700));
    m_vector.addElement(new StockData("UIS", "Unisys Corp.", 
      28.25, 29, -0.75, -2.59, 2576200));
    m_vector.addElement(new StockData("SNE", "Sony Corp.", 
      96.1875, 95.625, 1.125, 1.18, 330600));
    m_vector.addElement(new StockData("NOVL", "Novell Inc.", 
      24.0625, 24.375, -0.3125, -3.02, 6047900));
    m_vector.addElement(new StockData("HIT", "Hitachi, Ltd.", 
      78.5, 77.625, 0.875, 1.12, 49400));

    Collections.sort(m_vector, new 
      StockComparator(m_sortCol, m_sortAsc));
  }

  public int getRowCount() {
    return m_vector==null ? 0 : m_vector.size(); 
  }

  public int getColumnCount() { 
    return m_columns.length; 
  } 

  public String getColumnName(int column) {
    String str = m_columns[column].m_title;
    if (column==m_sortCol)
      str += m_sortAsc ? ">>" : "<<";
    return str;
  }
 
  public boolean isCellEditable(int nRow, int nCol) {
    return false;
  }

  public Object getValueAt(int nRow, int nCol) {
    if (nRow < 0 || nRow>=getRowCount())
      return "";
    StockData row = (StockData)m_vector.elementAt(nRow);
    switch (nCol) {
      case 0: return row.m_symbol;
      case 1: return row.m_name;
      case 2: return row.m_last;
      case 3: return row.m_open;
      case 4: return row.m_change;
      case 5: return row.m_changePr;
      case 6: return row.m_volume;
    }
    return "";
  }

  public String getTitle() {
    if (m_date==null)
      return "Stock Quotes";
    return "Stock Quotes at "+m_frm.format(m_date);
  }

  public int retrieveData(final java.util.Date date) {
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.setTime(date);
    int month = calendar.get(Calendar.MONTH)+1;
    int day = calendar.get(Calendar.DAY_OF_MONTH);
    int year = calendar.get(Calendar.YEAR);

    final String query = "SELECT data.symbol, symbols.name, "+
      "data.last, data.open, data.change, data.changeproc, "+
      "data.volume FROM DATA INNER JOIN SYMBOLS "+
      "ON DATA.symbol = SYMBOLS.symbol WHERE "+
      "month(data.date1)="+month+" AND day(data.date1)="+day+
      " AND year(data.date1)="+year;

    Thread runner = new Thread() {
      public void run() {
        try {
          // Load the JDBC-ODBC bridge driver
          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
          Connection conn = DriverManager.getConnection(
            "jdbc:odbc:Market", "admin", "");

          Statement stmt = conn.createStatement();
          ResultSet results = stmt.executeQuery(query);

          boolean hasData = false;
          while (results.next()) {
            if (!hasData) {
              m_vector.removeAllElements();
              hasData = true;
            }
            String  symbol = results.getString(1);
            String  name = results.getString(2);
            double  last = results.getDouble(3);
            double  open = results.getDouble(4);
            double  change = results.getDouble(5);
            double  changePr = results.getDouble(6);
            long volume = results.getLong(7);
            m_vector.addElement(new StockData(symbol, name, last, 
              open, change, changePr, volume));
          }
          results.close();
          stmt.close();
          conn.close();

          if (!hasData)    // We've got nothing
            m_result = 1;
        }
        catch (Exception e) {
          e.printStackTrace();
          System.err.println("Load data error: "+e.toString());
          m_result = -1;
        }
        m_date = date;
        Collections.sort(m_vector, 
          new StockComparator(m_sortCol, m_sortAsc));
        m_result = 0;
      }
    };
    runner.start();

    return m_result;
  }

  class ColumnListener extends MouseAdapter
  {
    protected JTable m_table;

    public ColumnListener(JTable table) {
      m_table = table;
    }

    public void mouseClicked(MouseEvent e) {
      TableColumnModel colModel = m_table.getColumnModel();
      int columnModelIndex = colModel.getColumnIndexAtX(e.getX());
      int modelIndex = colModel.getColumn(columnModelIndex).getModelIndex();

      if (modelIndex < 0)
        return;
      if (m_sortCol==modelIndex)
        m_sortAsc = !m_sortAsc;
      else
        m_sortCol = modelIndex;

      for (int i=0; i < m_columns.length; i++) {
        TableColumn column = colModel.getColumn(i);
        column.setHeaderValue(getColumnName(column.getModelIndex()));    
      }
      m_table.getTableHeader().repaint();  

      Collections.sort(m_vector, new 
        StockComparator(modelIndex, m_sortAsc));
      m_table.tableChanged(
        new TableModelEvent(StockTableData.this)); 
      m_table.repaint();  
    }
  }
}

class StockComparator implements Comparator
{
  protected int     m_sortCol;
  protected boolean m_sortAsc;

  public StockComparator(int sortCol, boolean sortAsc) {
    m_sortCol = sortCol;
    m_sortAsc = sortAsc;
  }

  public int compare(Object o1, Object o2) {
    if(!(o1 instanceof StockData) || !(o2 instanceof StockData))
      return 0;
    StockData s1 = (StockData)o1;
    StockData s2 = (StockData)o2;
    int result = 0;
    double d1, d2;
    switch (m_sortCol) {
      case 0:    // symbol
        String str1 = (String)s1.m_symbol.m_data;
        String str2 = (String)s2.m_symbol.m_data;
        result = str1.compareTo(str2);
        break;
      case 1:    // name
        result = s1.m_name.compareTo(s2.m_name);
        break;
      case 2:    // last
        d1 = s1.m_last.doubleValue();
        d2 = s2.m_last.doubleValue();
        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
        break;
      case 3:    // open
        d1 = s1.m_open.doubleValue();
        d2 = s2.m_open.doubleValue();
        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
        break;
      case 4:    // change
        d1 = ((Fraction)s1.m_change.m_data).doubleValue();
        d2 = ((Fraction)s2.m_change.m_data).doubleValue();
        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
        break;
      case 5:    // change %
        d1 = ((Double)s1.m_changePr.m_data).doubleValue();
        d2 = ((Double)s2.m_changePr.m_data).doubleValue();
        result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
        break;
      case 6:    // volume
        long l1 = s1.m_volume.longValue();
        long l2 = s2.m_volume.longValue();
        result = l1<l2 ? -1 : (l1>l2 ? 1 : 0);
        break;
    }

    if (!m_sortAsc)
      result = -result;
    return result;
  }

  public boolean equals(Object obj) {
    if (obj instanceof StockComparator) {
      StockComparator compObj = (StockComparator)obj;
      return (compObj.m_sortCol==m_sortCol) && 
        (compObj.m_sortAsc==m_sortAsc);
    }
    return false;
  }
}
